//  -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	Smart.Common
//  File name:	WebExts.cs
//  Developer:	Solomatov Igor
//  Created:	15.04.2012
// 
//  -------------------- iSharePoint -------------------- //

using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Smart
{
	[DebuggerStepThrough]
	public static class WebExts
	{
		public static string GetPageName()
		{
			var fullPath = HttpContext.Current.Request.Url.AbsolutePath;

			var fileName = Path.GetFileName(fullPath);

			return fileName;
		}

		public static string GetPageName(this Control ctrl)
		{
			var fullPath = ctrl.Page.Request.Url.AbsolutePath;

			var fileName = Path.GetFileName(fullPath);

			return fileName;
		}

		public static Page GetPage()
		{
			var current = HttpContext.Current;

			return current != null ? current.Handler as Page : null;
		}

		public static bool IsPage()
		{
			var current = HttpContext.Current;

			return current != null && current.Handler is Page;
		}

		/// <summary>
		/// Checks whether url is full
		/// </summary>
		public static UrlType DetectUrlType(this string url)
		{
			if (url.IsNullOrEmpty())
				return UrlType.None;

			var protocolEndIdx = url.IndexOf(@"://", StringComparison.OrdinalIgnoreCase);

			if (protocolEndIdx > 0)
			{
				var firstSlashIdx = url.IndexOf(@"/", StringComparison.OrdinalIgnoreCase);

				if (protocolEndIdx < firstSlashIdx)
					return UrlType.Abolute;
			}

			return
				url.StartsWith(@"/", StringComparison.OrdinalIgnoreCase)
					? UrlType.ServerRelative
					: UrlType.SiteRelative;
		}

		/// <summary>
		/// Find control recursive
		/// </summary>
		public static T FindControlRecursive<T>(this Control control)
			where T : Control
		{
			if (control == null)
				return default(T);

			var controls = control.Controls;

			if (controls.Count <= 0)
				return default(T);

			for (var i = 0; i < controls.Count; i++)
			{
				if (controls[i] is T)
					return controls[i] as T;

				var found = FindControlRecursive<T>(controls[i]);

				if (found != null)
					return found;
			}

			return default(T);
		}

		/// <summary>
		/// Find Control Recursive
		/// </summary>
		public static Control FindControlRecursive(this Control control, string id)
		{
			if (control == null)
				return null;

			var controls = control.Controls;

			if (controls.Count <= 0)
				return null;

			for (var i = 0; i < controls.Count; i++)
			{
				var ctrl = controls[i];

				if (ctrl.ID.EqIC(id))
					return ctrl;

				var found = FindControlRecursive(ctrl, id);

				if (found != null)
					return found;
			}

			return null;
		}

		/// <summary>
		/// Checks whether validation is required
		/// </summary>
		public static bool IsValidationRequired(this Page page)
		{
			if (!page.IsPostBack)
				return false;

			var ctrlId = page.Request.Form[Page.postEventSourceID];

			if (ctrlId.IsNullOrEmpty())
				return true;

			var ctrl = page.FindControlRecursive(ctrlId) as IButtonControl;

			return
				ctrl != null && ctrl.CausesValidation;
		}

		public static bool SafeIsValid(this Page page, bool validate)
		{
			// ReSharper disable EmptyGeneralCatchClause
			try
			{
				return
					page.IsValid;
			}
			catch
			{
			}
			// ReSharper restore EmptyGeneralCatchClause

			if (validate)
			{
				page.Validate();

				return
					page.IsValid;
			}


			return false;
		}

		/// <summary>
		/// Find Parent Control
		/// </summary>
		public static T FindParentControl<T>(this Control control)
			where T : Control
		{
			var parent = control;

			while (parent != null)
			{
				if (parent is T)
					return parent as T;

				parent = parent.Parent;
			}

			return null;
		}

		/// <summary>
		/// Detect DataField
		/// </summary>
		public static string GetDataField(this DataGridColumn column)
		{
			string dataField;

			var boundColumn = column as BoundColumn;

			if (boundColumn != null)
			{
				dataField = boundColumn.DataField;
			}
			else
			{
				var hyperColumn = column as HyperLinkColumn;

				dataField =
					hyperColumn != null
						? hyperColumn.DataTextField
						: column.SortExpression;
			}

			return dataField;
		}

		/// <summary>
		/// Export grid data to Excel, write data to StringBuilder
		/// </summary>
		public static StringBuilder ExportToExcel(this DataGrid grid, IDictionary<string, string> columnHeaders)
		{
			var buffer = new StringBuilder();

			H.LT("Exporting: grid {0}", grid.ID);

			buffer.Append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n</head>\n<body>\n");
			buffer.Append("<table border=\"1\" cellspacing=\"0\" cellpadding=\"2\" bordercolor=\"black\" style=\"border-collapse:collapse;\">\n");

			// load columns
			var gcs = grid.Columns.OfType<DataGridColumn>().Where(gc => (gc is BoundColumn || gc is HyperLinkColumn) && gc.Visible).ToArray();
			var ecs = gcs.Select(gc => gc.GetDataField()).ToArray();
			var ech = gcs.Select(gc => gc.HeaderText).ToArray();

			// output group columns
			if (columnHeaders != null && columnHeaders.Count > 0)
			{
				buffer.Append("<tr>");

				for (var eci = 0; eci < ecs.Length; )
				{
					var ec = ecs[eci];
					var group = columnHeaders.SafeGet(ec);

					var ieci = eci + 1;
					var span = 1;

					while (ieci < ecs.Length)
					{
						var iec = ecs[ieci];
						var ig = columnHeaders.SafeGet(iec);

						if (!string.Equals(group, ig, StringComparison.CurrentCultureIgnoreCase))
						{
							eci = ieci;
							break;
						}

						span++;
						ieci++;
					}

					if (ieci >= ecs.Length)
						eci = ieci;

					buffer.AppendFormat("<td colspan=\"{0}\">{1}</td>", span, @group);
				}

				buffer.Append("</tr>\n");
			}

			// output column names

			buffer.Append("<tr>");

			for (var eci = 0; eci < ech.Length; eci++)
			{
				var ch = ech[eci];

				buffer.AppendFormat("<td>{0}</td>", ch);
			}

			buffer.Append("</tr>\n");

			// output data
			var ods = grid.DataSource;

			if (ods == null)
				throw new InvalidDataException("grid.DataSource is null!");

			string filtering = null;
			string sorting = null;

			DataRow[] rows = null;

			DataTable dt = null;

			if (ods is DataSet)
			{
				dt = ((DataSet)ods).Tables[grid.DataMember];
			}
			else if (ods is DataTable)
			{
				dt = (DataTable)ods;
			}
			else if (ods is DataView)
			{
				var dv = (DataView)ods;

				if (dv.Table != null)
				{
					dt = dv.Table;

					sorting = dv.Sort ?? "";
					filtering = dv.RowFilter ?? "";
				}
			}

			if (dt != null)
				rows = dt.Select(filtering, sorting);

			if (rows == null)
				throw new Exception("Can't export, no data available (rows is null)");

			for (var ri = 0; ri < rows.Length; ri++)
			{
				var row = rows[ri];

				buffer.Append("<tr>");

				for (var eci = 0; eci < ecs.Length; eci++)
				{
					var ec = ecs[eci];

					buffer.AppendFormat("<td>{0}</td>", row[ec].SToStr("&nbsp;"));
				}

				if (ri % 1000 == 0)
				{
					H.LT("Exporting: {0} row", ri);
				}

				buffer.Append("</tr>\n");
			}

			buffer.Append("</table>\n");
			buffer.Append("</body>\n");
			buffer.Append("</html>\n");

			H.LT("Exporting: grid {0} exported {1} rows", grid.ID, rows.Length);

			return buffer;
		}

		/// <summary>
		/// Export grid data to Excel, write data to response
		/// </summary>
		public static void OutputToExcelInResponse(this DataGrid grid, IDictionary<string, string> columnHeaders)
		{
			var buffer = ExportToExcel(grid, columnHeaders);

			var exportFileName = "export-" + System.IO.Path.GetFileNameWithoutExtension(grid.GetPageName()) + ".xls";

			var response = grid.Page.Response;

			response.Clear();
			response.Buffer = true;
			response.ContentType = "application/vnd.ms-excel";
			response.ContentEncoding = Encoding.UTF8;
			response.Charset = "";
			response.AddHeader("Content-Disposition", "attachment;filename=\"" + exportFileName + "\"");
			response.Write(buffer);
			response.End();
		}

		/// <summary>
		/// Find node by text path
		/// </summary>
		public static TreeNode FindNodeByTextPath(this TreeNodeCollection nodes, string path, char separator)
		{
			if (path.IsNullOrEmpty())
				return null;

			var pathParts = path.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries);

			TreeNode iNode = null;
			var iNodes = nodes;

			foreach (var pathPart in pathParts)
			{
				try
				{
					foreach (TreeNode node in iNodes)
					{
						if (!node.Text.EqIC(pathPart)) continue;

						iNode = node;

						break;
					}
				}
				catch (Exception x)
				{
					H.LX("FindNodeByTextPath", x);

					iNode = null;
				}

				if (iNode == null)
					break;

				iNodes = iNode.ChildNodes;
			}

			return iNode;
		}

		/// <summary>
		/// Find node by text path
		/// </summary>
		public static TreeNode FindNodeByValue(this TreeNodeCollection nodes, string path)
		{
			if (path.IsNullOrEmpty())
				return null;

			TreeNode iNode = null;

			try
			{
				foreach (TreeNode node in nodes)
				{
					if (!node.Value.EqIC(path)) continue;

					iNode = node;

					break;
				}
			}
			catch (Exception x)
			{
				H.LX("FindNodeByValue", x);

				iNode = null;
			}

			return iNode;
		}

		/// <summary>
		/// Find node by text path
		/// </summary>
		public static TreeNode FindNodeByValuePath(this TreeNodeCollection nodes, string path, char separator)
		{
			if (path.IsNullOrEmpty())
				return null;

			var pathParts = path.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries);

			TreeNode iNode = null;
			var iNodes = nodes;

			foreach (var pathPart in pathParts)
			{
				try
				{
					foreach (TreeNode node in iNodes)
					{
						if (!node.Value.EqIC(pathPart)) continue;

						iNode = node;

						break;
					}
				}
				catch (Exception x)
				{
					H.LX("FindNodeByValuePath", x);

					iNode = null;
				}

				if (iNode == null)
					break;

				iNodes = iNode.ChildNodes;
			}

			return iNode;
		}

		/// <summary>
		/// Find index by value
		/// </summary>
		public static int FindIndexByValue(this ListItemCollection items, string value)
		{
			for (int i = 0, iMax = items.Count; i < iMax; i++)
			{
				var item = items[i];

				if (item.Value.EqIC(value))
					return i;
			}

			return -1;
		}
	}
}